import xlrd

from .preTestcase import TestcaseJson
from ..hrunutils import strStrip, checkStr2Int_Bool, mergeDictList


class HrunParser_excel():
    def __init__(self,  workdir = ''):
        self.workdir =workdir

    def parserExcel(self, workbook):

        return self.fromSheet2List(workbook.sheets[0])

    def fromSheet2List_tsuite(self, sheet, workbook):
        self.workBook = workbook

        # 按照 testsuite模式进行解析
        tcRet = []
        tcDict = {}
        tlist = self.fromSheet2List(sheet)

        tctmp ={}   # Tsuite 对象的tc
        dictTC ={}  # sheet testcase dict对象
        for item in tlist:
            if "config" in item:
                tcDict['config'] = item['config']
            else:
                # 处理testcase
                if item.get('skip', False):  # skip为true 则跳过
                    continue

                tc = item['testcase']    # item.pop('testcase')

                otc = self.fromSheet2List(workbook.sheet_by_name(tc))[0]

                otc['config']['tcname'] = item['testcase']

                dictTC[item['name']] = otc
                tctmp[item['name']] =item

                # tctmp.append(item)

        tcDict['testcases'] = tctmp

        for kName, vTC in dictTC.items():
            # 预处理 Tsuite
            TsuiteJson(tcDict, [vTC]).handle()
            # 预处理 Testcase
            TestcaseJson().preHandleConfig(vTC, self.workdir)

            tcDict['testcases'][kName]['testcase_def'] = vTC

        tcRet.append(tcDict)

        return tcRet

    def fromSheet2Dict_sheetsuite(self, sheet, workbook):
        # 按照 sheetsuite 模式进行解析
        tcDict = {}
        tlist = self.fromSheet2List(sheet)

        tctmp =[]
        for item in tlist:
            if "config" in item:
                tcDict['config'] = item['config']
            else:
                if item.get('skip', False):  # skip为true 则跳过
                    continue

                # 处理testcase
                tc = item['testcase'] # item.pop('testcase')

                tctmp.append(item)

        tcDict['testcases'] = tctmp


        osheets = []
        # 执行TestSuite 列表定义，并生成Testcase 列表
        for tc in tcDict['testcases']:
            tcsheetname = tc['testcase']
            dictTC = self.fromSheet2List(workbook.sheet_by_name(tcsheetname))[0]

            dictTC['config']['tcname'] = tcsheetname
            osheets.append(dictTC)

        # 预处理tsuite config 到 testcase config
        # 处理 headers、variables
        # 将tsuite config 的header ，复制到testcase config header，并排除重复内容
        # 将tsuite.variables 分配到 testcase.config.variables
        TsuiteJson(tcDict, osheets).handleSheetsuite()

        for tc in osheets:
            # 预处理 Testcase
            TestcaseJson().preHandleConfig(tc, self.workdir)

        return osheets

    def fromSheet2List_prepare(self, sheet):
        # 从sheet提取 testcase json，并进行预处理，包括：headers、validate

        otcs = self.fromSheet2List(sheet)

        # 预处理 Testcase
        TestcaseJson().preHandleConfig(otcs, self.workdir)

        return otcs


    def fromSheet2List(self, sheet):
        # # 从sheet提取 testcase list json

        # 获取总行数
        rosw = sheet.nrows
        tmplist = []

        tcDict = {}
        # 根据总行数进行读取
        iRow: int = 0
        while (iRow < rosw):
            # 过滤空行
            if sheet.row_values(iRow, 0, 1)[0] != '' or sheet.row_values(iRow, 1, 2)[0] != '':
                tmpdict = {}
                # 解析config
                if sheet.row_values(iRow, 0, 1)[0] == 'config':
                    tcDict['config'] = self.parserConfig2Dict(sheet, iRow)
                    # tmplist.append(self.parserConfig(sheet, i))

                    iRow += 2
                elif sheet.row_values(iRow, 0, 1)[0] in ['teststeps', 'api']:
                    tcDict['teststeps'] = self.parserTestcase2List(sheet, iRow, sheet.row_values(iRow, 0, 1)[0])
                    # tmplist.extend(self.parserTestcase(sheet, i, sheet.row_values(i, 0, 1)[0]))
                    # tmplist.append(self.parserTestcase(sheet, i, sheet.row_values(i, 0, 1)[0]))
                    break
                elif sheet.row_values(iRow, 0, 1)[0] in ['testcases', 'apis', 'tests']:
                    tmplist.extend(self.parserTestcase2List(sheet, iRow, sheet.row_values(iRow, 0, 1)[0]))
                    # tmplist.append(self.parserTestcase(sheet, i, sheet.row_values(i, 0, 1)[0]))
                    break
                elif sheet.row_values(iRow, 0, 1)[0] == '=':
                    tmplist.extend(self.parserTestcase2List(sheet, iRow - 1, 'testcases'))
                    # tmplist.append(self.parserTestcase(sheet, i - 1, 'testcases'))
                    break
                else:
                    rowvalues = sheet.row_values(iRow)
                    # 讲每一行的内容添加进去
                    tmplist.append(rowvalues)
                    #     去除大标题第一行进行切割处理
            iRow += 1

        tmplist.append(tcDict)
        # self.ObjTestcase = tmplist
        return tmplist

    def parserConfig2Dict(self, sheet, irow):
        dict_field = {}

        listFields = sheet.row_values(irow + 1)
        listValues = sheet.row_values(irow + 2)
        # 校验字段
        if listFields[0] == '=':
            dict_field = self._parserFields2Dict(listFields, listValues)

        else:
            print('字段行必须以 = 开头')
        return dict_field

    def parserTestcase2List(self, sheet, irow, name='testcases'):
        list_tc = []
        listFields = sheet.row_values(irow + 1)
        # 校验字段
        if listFields[0] == '=':
            for xrow in range(irow + 2, sheet.nrows):
                if sheet.row_values(xrow, 1, 2)[0] != '':
                    list_tc.append(self._parserFields2Dict(listFields, sheet.row_values(xrow)))
                    # list_tc.append({name:self.parserFields(listFields, sheet.row_values(xrow))})

        else:
            print('字段行必须以 = 开头')
        return list_tc

    def _parserFields2Dict(self, listfields, listvalues):
        dict_fields = {}

        def mergeRequest(sfield, svalue, dict_request={}):
            # 合并 request字段到 dict_request
            dict_request[sfield.split('.')[1]] = svalue
            return dict_request

        for icol in range(1, len(listfields)):  # 遍历字段
            xfield = listfields[icol]  # 字段名
            svalue = listvalues[icol]  # 字段值

            if svalue == '':  # 如果为空行即跳过
                pass
            else:
                # field 需要解析value
                if xfield in ['variables', 'parameters',
                              'request.params', 'request.data']:
                    svalue = self.parserValueToDict(svalue)
                elif xfield in ['request.json']:
                    # json 兼容
                    if svalue.startswith('{'):
                        svalue = eval(svalue)
                    else:
                        svalue = self.parserValueToDict(svalue)
                elif xfield in ['request.headers', 'headers']:
                    # 值为 string 类型
                    svalue = self.parserValueToDict(svalue, value2string=True)
                elif xfield in ['extract', 'validate']:
                    # list格式类型
                    svalue = self.parserValue2List(svalue)
                elif xfield in ['verify','skiped','skip']:
                    #解析verify false\true
                    svalue = False if svalue==0 else True
                elif xfield in ['output']:
                    svalue = self.parserValue2ArrayList(svalue)
                elif xfield == 'testcase':
                    # 处理 testcase 对应的sheet   =   testcase_def
                    dict_fields['testcase_def'] = self.fromSheet2List(self.workBook.sheet_by_name(svalue))[0]

                if xfield.startswith('request'):
                    # 合并request字段为 dict
                    dict_fields['request'] = mergeRequest(xfield, svalue)
                else:
                    dict_fields[xfield] = svalue
        return dict_fields

    def parserValue2List(self, svalue):
        valist = []
        tmplist = svalue.splitlines()
        i = 0
        while (i < len(tmplist)):
            s = tmplist[i]
            skey, svalue = self.parserValue2KeyValue(s.strip())

            if svalue == '':  # 处理多行value
                pass
            else:
                valist.append({skey: self.parserKvalue(svalue)})

            i += 1

        return valist

    def parserValue2ArrayList(self, svalue):
        return svalue.splitlines()


    def parserMultiLineToList(self, slist, index=0):
        tlist = []
        for i in range(index, len(slist)):
            tlist.append(self.parserKvalue(strStrip(slist[i])))
        return tlist

    def parserKvalue(self, svalue, value2string=False):
        if svalue.startswith('['):
            svalue = svalue.replace('[', '').replace(']', '').strip()

            if svalue.startswith('{'):  # 解析dict
                return eval(svalue)

            xlist = svalue.split(',', 1)
            # tlist =[str(self.strip(s)) for s in xlist]
            # for s in xlist:
            #     tlist.append(self.strip(s) )

            return [checkStr2Int_Bool(s) for s in xlist]
        else:
            return checkStr2Int_Bool(svalue) if not value2string else svalue.strip()

    def parserValueToDict(self, svalue, value2string=False):
        tmpdict = {}
        tmplist = svalue.splitlines()

        i = 0
        while (i < len(tmplist)):
            s = tmplist[i]
            if s != '':  # 空行跳过
                skey, svalue = self.parserValue2KeyValue(s.strip())

                if svalue == '':  # 处理多行value
                    tmpdict[skey.strip()] = self.parserMultiLineToList(tmplist, i + 1)
                    break
                else:
                    tmpdict[skey.strip()] = self.parserKvalue(svalue, value2string)
            i += 1

        return tmpdict

    def parserValue2KeyValue(self, svalue):
        """
        转化 key:value 为两个变量
        :param svalue:
        :return:  返回key、value 两个变量参数
        """
        xkeyvalue = svalue.split(':', 1)
        xkey = strStrip(xkeyvalue[0])
        return xkey, xkeyvalue[1].strip() if len(xkeyvalue) == 2 else ''



class TsuiteJson:
    '''
    预处理testsuite &testcase
    '''

    def __init__(self, oSuite, oTestcases):
        self.testsuite = oSuite
        self.testcases = oTestcases

    # 处理 config.headers  config.validate  config.variables
    # testcase.variables

    def handle(self):
        for tc in self.testcases:
            self.handleConfig('headers', tc)
            self.handleConfig('validate', tc)
            # self.handleConfig('variables', tc)
            # self.handleTestcase('variables', tc)


    # testsuite.config < testsuite.testcase.item < testsuite.testcases.tc.config
    def handleSheetsuite(self):
        # src = self.testsuite['config']

        for tc in self.testcases:
            self.handleConfig('headers', tc)
            self.handleConfig('validate', tc)
            self.handleVars(tc)

    def getTCSvar(self, ts_tcs, tcname, oname):
        if isinstance(ts_tcs, list):
            for xtc in ts_tcs:
                if xtc['testcase'] == tcname:
                    return xtc.get(oname, {})
            else:
                return None
        else:
            for k, xtc in ts_tcs.items():
                if xtc['testcase'] == tcname:
                    return xtc.get(oname, {})
            else:
                return None

    def handleVars(self, otc):

        # 处理sheetsuite 模式下的 variables
        oname = 'variables'
        # testsuite.config.variables < testsuite.testcase.variables < testsuite.testcases.tc.config.variables
        tcname = otc['config']['tcname']

        # testsuite.config.variables
        tsconfigVars = self.testsuite['config'][oname]

        # testsuite.testcase.variables
        tscaseVars = self.getTCSvar(self.testsuite['testcases'], tcname, oname)
        tscaseVars = self._handleItems(tsconfigVars, tscaseVars)

        # testsuite.testcases.tc.config.variables
        tcconfigVars = otc['config'].get(oname, {})
        otc['config'][oname] = self._handleItems(tscaseVars, tcconfigVars)

    def handleConfig(self, oname, otc):
        # 处理config元素
        oconfig = otc['config']
        if oname not in self.testsuite['config'] or oname not in oconfig:
            return

        oconfig[oname] = self._handleItems(self.testsuite['config'][oname], oconfig[oname])

    def handleTestcase(self, oname, otc):

        oconfig = otc['config']

        ts_tcs = self.testsuite['testcases']

        # 获取tcname   sheet名称
        tcname = otc['config']['tcname']

        ovars = self.getTCSvar(ts_tcs, tcname, oname)
        if ovars is None or ovars == '':
            return

        # 合并 tsuit.testcase.variables 到 testcase.variables
        oconfig[oname] = self._handleItems(ovars, oconfig.get(oname,{}))   # if oname not in oconfig else oconfig[oname])


    def _handleItems(self, srcs, target):
        # 1、取出 源list/dict
        # 2、扫描 目标list/dict,

        return mergeDictList(target, srcs)


def loadxls():
    wb = xlrd.open_workbook("d:/demo_httprunner.xls")
    jj = HrunParser_excel().fromSheet2List(wb.sheet_by_name('demo-testcase-get-token'))
    print(jj)
    # addapi(jj[0], 4, 2)


if __name__ == "__main__":
    loadxls()
